package com.bestv.database.dao;

import com.bestv.database.vo.Base;
import com.bestv.utils.cache.MemcacheHelper;
import com.bestv.utils.database.DBConnectionManager;
import com.bestv.utils.database.JDBCHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.util.ArrayList;

/**
 * Created by Henry on 14-5-21.
 */
public abstract class BaseDao<T extends Base> {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private Class entityClass;

    public BaseDao() {
        ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
        entityClass = (Class) type.getActualTypeArguments()[0];
    }

    public T findById(Long id) {
        T obj = null;
        try {
            obj = (T) entityClass.getConstructor().newInstance();
        } catch (NoSuchMethodException e) {
            logger.error("No such method.", e);
        } catch (InstantiationException e) {
            logger.error("Error on instantiation.", e);
        } catch (IllegalAccessException e) {
            logger.error("Error on illegal access.", e);
        } catch (InvocationTargetException e) {
            logger.error("Error on invocation target.", e);
        }
        obj.setId(id);

        String cacheIdKey = obj.getCacheIdKey();
        T object = (T) MemcacheHelper.getInstance().getObject(cacheIdKey);
        if (object != null) return object.isValid() ? object : null;

        String sqlFormat = "SELECT * FROM %s WHERE Id=? LIMIT 1";
        String sql = String.format(sqlFormat, entityClass.getSimpleName().toLowerCase());
        Connection conn = DBConnectionManager.getSlaveConnection();
        ArrayList<Object> rs = JDBCHelper.executeQuery(conn, sql, entityClass, id);
        JDBCHelper.close(conn);

        if (rs.size() == 1) {
            obj = (T) rs.get(0);
            String cacheMediaCodeKey = obj.getCacheMediaCodeKey();
            MemcacheHelper.getInstance().addObject(cacheMediaCodeKey, obj);
        }

        MemcacheHelper.getInstance().addObject(cacheIdKey, obj);
        return obj.isValid() ? obj : null;
    }

    public T findByMediaCode(String mediaCode) {
        T obj = null;
        try {
            obj = (T) entityClass.getConstructor().newInstance();
        } catch (NoSuchMethodException e) {
            logger.error("No such method.", e);
        } catch (InstantiationException e) {
            logger.error("Error on instantiation.", e);
        } catch (IllegalAccessException e) {
            logger.error("Error on illegal access.", e);
        } catch (InvocationTargetException e) {
            logger.error("Error on invocation target.", e);
        }
        obj.setMediaCode(mediaCode);

        String cacheMediaCodeKey = obj.getCacheMediaCodeKey();
        T object = (T) MemcacheHelper.getInstance().getObject(cacheMediaCodeKey);
        if (object != null) return object.isValid() ? object : null;

        String sqlFormat = "SELECT * FROM %s WHERE MediaCode=? LIMIT 1";
        String sql = String.format(sqlFormat, entityClass.getSimpleName().toLowerCase());
        Connection conn = DBConnectionManager.getSlaveConnection();
        ArrayList<Object> rs = JDBCHelper.executeQuery(conn, sql, entityClass, mediaCode);
        JDBCHelper.close(conn);

        if (rs.size() == 1) {
            obj = (T) rs.get(0);
            String cacheIdKey = obj.getCacheIdKey();
            MemcacheHelper.getInstance().addObject(cacheIdKey, obj);
        }

        MemcacheHelper.getInstance().addObject(cacheMediaCodeKey, obj);
        return obj.isValid() ? obj : null;
    }

    public T first() {
        String sqlFormat = "SELECT * FROM %s LIMIT 1";
        String sql = String.format(sqlFormat, entityClass.getSimpleName().toLowerCase());
        Connection conn = DBConnectionManager.getSlaveConnection();
        ArrayList<Object> rs = JDBCHelper.executeQuery(conn, sql, entityClass);
        JDBCHelper.close(conn);
        if (rs.size() == 1) return (T) rs.get(0);
        return null;
    }
}
